home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / amiga / gui / x / xfig.lha / src / x11 / e_scale.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-26  |  25.6 KB  |  1,054 lines

  1. /*
  2.  * FIG : Facility for Interactive Generation of figures
  3.  * Copyright (c) 1985 by Supoj Sutanthavibul
  4.  *
  5.  * "Permission to use, copy, modify, distribute, and sell this software and its
  6.  * documentation for any purpose is hereby granted without fee, provided that
  7.  * the above copyright notice appear in all copies and that both the copyright
  8.  * notice and this permission notice appear in supporting documentation. 
  9.  * No representations are made about the suitability of this software for 
  10.  * any purpose.  It is provided "as is" without express or implied warranty."
  11.  */
  12.  
  13. #include "fig.h"
  14. #include "resources.h"
  15. #include "mode.h"
  16. #include "object.h"
  17. #include "paintop.h"
  18. #include "u_create.h"
  19. #include "u_draw.h"
  20. #include "u_elastic.h"
  21. #include "u_search.h"
  22. #include "u_undo.h"
  23. #include "w_canvas.h"
  24. #include "w_mousefun.h"
  25.  
  26. static int    init_box_scale();
  27. static Boolean    init_boxscale_ellipse();
  28. static Boolean    init_boxscale_line();
  29. static Boolean    init_boxscale_compound();
  30. static int    assign_newboxpoint();
  31. static int    boxrelocate_ellipsepoint();
  32.  
  33. static int    init_center_scale();
  34. static int    init_scale_arc();
  35. static int    init_scale_compound();
  36. static int    init_scale_ellipse();
  37. static int    init_scale_line();
  38. static int    init_scale_spline();
  39. static int    rescale_points();
  40. static int    relocate_ellipsepoint();
  41. static int    relocate_arcpoint();
  42.  
  43. static int    fix_scale_arc();
  44. static int    fix_scale_spline();
  45. static int    fix_scale_line();
  46. static int    fix_scale_ellipse();
  47. static int    fix_boxscale_ellipse();
  48. static int    fix_boxscale_line();
  49. static int    fix_scale_compound();
  50. static int    fix_boxscale_compound();
  51.  
  52. static int    cancel_scale_arc();
  53. static int    cancel_scale_spline();
  54. static int    cancel_scale_line();
  55. static int    cancel_scale_ellipse();
  56. static int    cancel_boxscale_ellipse();
  57. static int    cancel_boxscale_line();
  58. static int    cancel_scale_compound();
  59. static int    cancel_boxscale_compound();
  60. static int    prescale_compound();
  61.  
  62. scale_selected()
  63. {
  64.     set_mousefun("scale box", "scale about center", "");
  65.     canvas_kbd_proc = null_proc;
  66.     canvas_locmove_proc = null_proc;
  67.     init_searchproc_left(init_box_scale);
  68.     init_searchproc_middle(init_center_scale);
  69.     canvas_leftbut_proc = object_search_left;
  70.     canvas_middlebut_proc = object_search_middle;
  71.     canvas_rightbut_proc = null_proc;
  72.     set_cursor(pick15_cursor);
  73.     reset_action_on();
  74. }
  75.  
  76. static
  77. init_box_scale(obj, type, x, y, px, py)
  78.     char       *obj;
  79.     int            type, x, y;
  80.     int            px, py;
  81. {
  82.     switch (type) {
  83.     case O_POLYLINE:
  84.     cur_l = (F_line *) obj;
  85.     if (!init_boxscale_line(px, py))    /* non-box line */
  86.         return;
  87.     break;
  88.     case O_ELLIPSE:
  89.     cur_e = (F_ellipse *) obj;
  90.     if (!init_boxscale_ellipse(px, py))    /* selected center, ignore */
  91.         return;
  92.     break;
  93.     case O_COMPOUND:
  94.     cur_c = (F_compound *) obj;
  95.     if (!init_boxscale_compound(px, py))    /* non-box compound */
  96.         return;
  97.     break;
  98.     default:
  99.     return;
  100.     }
  101.     set_mousefun("new posn", "", "cancel");
  102.     draw_mousefun_canvas();
  103.     canvas_middlebut_proc = null_proc;
  104. }
  105.  
  106. static
  107. init_center_scale(obj, type, x, y, px, py)
  108.     char       *obj;
  109.     int            type, x, y, px, py;
  110. {
  111.     double        dx, dy, l;
  112.  
  113.     cur_x = from_x = px;
  114.     cur_y = from_y = py;
  115.     constrained = BOX_SCALE;
  116.     switch (type) {
  117.     case O_POLYLINE:
  118.     cur_l = (F_line *) obj;
  119.     if (!init_scale_line()) /* selected center */
  120.         return;
  121.     break;
  122.     case O_SPLINE:
  123.     cur_s = (F_spline *) obj;
  124.     if (!init_scale_spline())    /* selected center */
  125.         return;
  126.     break;
  127.     case O_ELLIPSE:
  128.     cur_e = (F_ellipse *) obj;
  129.     if (!init_scale_ellipse())    /* selected center */
  130.         return;
  131.     break;
  132.     case O_ARC:
  133.     cur_a = (F_arc *) obj;
  134.     if (!init_scale_arc())    /* selected center */
  135.         return;
  136.     break;
  137.     case O_COMPOUND:
  138.     cur_c = (F_compound *) obj;
  139.     init_scale_compound();
  140.     break;
  141.     }
  142.  
  143.     dx = (double) (from_x - fix_x);
  144.     dy = (double) (from_y - fix_y);
  145.     l = sqrt(dx * dx + dy * dy);
  146.     cosa = fabs(dx / l);
  147.     sina = fabs(dy / l);
  148.  
  149.     set_mousefun("", "new posn", "cancel");
  150.     draw_mousefun_canvas();
  151.     canvas_leftbut_proc = null_proc;
  152. }
  153.  
  154. static
  155. wrapup_scale()
  156. {
  157.     reset_action_on();
  158.     scale_selected();
  159.     draw_mousefun_canvas();
  160. }
  161.  
  162. /*************************  ellipse  *******************************/
  163.  
  164. static        Boolean
  165. init_boxscale_ellipse(x, y)
  166.     int            x, y;
  167. {
  168.     double        dx, dy, l;
  169.  
  170.     if (cur_e->type == T_ELLIPSE_BY_RAD ||
  171.     cur_e->type == T_CIRCLE_BY_RAD) {
  172.     put_msg("Can't use box scale on selected object");
  173.     return False;
  174.     }
  175.     if (x == cur_e->start.x && y == cur_e->start.y) {
  176.     fix_x = cur_e->end.x;
  177.     fix_y = cur_e->end.y;
  178.     cur_x = from_x = x;
  179.     cur_y = from_y = y;
  180.     } else if (x == cur_e->end.x && y == cur_e->end.y) {
  181.     fix_x = cur_e->start.x;
  182.     fix_y = cur_e->start.y;
  183.     cur_x = from_x = x;
  184.     cur_y = from_y = y;
  185.     } else {
  186.     put_msg("Can't use box scale on selected object");
  187.     return False;
  188.     }
  189.     cur_angle = cur_e->angle;
  190.  
  191.     if (cur_x == fix_x || cur_y == fix_y) {
  192.     put_msg("Can't use box scale on selected object");
  193.     return False;
  194.     }
  195.     set_action_on();
  196.     toggle_ellipsemarker(cur_e);
  197.     constrained = BOX_SCALE;
  198.     dx = (double) (cur_x - fix_x);
  199.     dy = (double) (cur_y - fix_y);
  200.     l = sqrt(dx * dx + dy * dy);
  201.     cosa = fabs(dx / l);
  202.     sina = fabs(dy / l);
  203.  
  204.     set_temp_cursor(crosshair_cursor);
  205.     if (cur_e->type == T_CIRCLE_BY_DIA) {
  206.     canvas_locmove_proc = constrained_resizing_cbd;
  207.     elastic_cbd();
  208.     } else {
  209.     canvas_locmove_proc = constrained_resizing_ebd;
  210.     elastic_ebd();
  211.     }
  212.     canvas_leftbut_proc = fix_boxscale_ellipse;
  213.     canvas_rightbut_proc = cancel_boxscale_ellipse;
  214.     return True;
  215. }
  216.  
  217. static
  218. cancel_boxscale_ellipse()
  219. {
  220.     if (cur_e->type == T_CIRCLE_BY_DIA)
  221.     elastic_cbd();
  222.     else
  223.     elastic_ebd();
  224.     toggle_ellipsemarker(cur_e);
  225.     wrapup_scale();
  226. }
  227.  
  228. static
  229. fix_boxscale_ellipse(x, y)
  230.     int            x, y;
  231. {
  232.     if (cur_e->type == T_CIRCLE_BY_DIA)
  233.     elastic_cbd();
  234.     else
  235.     elastic_ebd();
  236.     adjust_box_pos(x, y, from_x, from_y, &cur_x, &cur_y);
  237.     new_e = copy_ellipse(cur_e);
  238.     boxrelocate_ellipsepoint(new_e, cur_x, cur_y);
  239.     change_ellipse(cur_e, new_e);
  240.     toggle_ellipsemarker(new_e);
  241.     wrapup_scale();
  242. }
  243.  
  244. static
  245. boxrelocate_ellipsepoint(ellipse, x, y)
  246.     F_ellipse       *ellipse;
  247.     int            x, y;
  248. {
  249.     int            dx, dy;
  250.  
  251.     set_temp_cursor(wait_cursor);
  252.     draw_ellipse(ellipse, ERASE);
  253.     if (ellipse->start.x == fix_x)
  254.     ellipse->end.x = x;
  255.     if (ellipse->start.y == fix_y)
  256.     ellipse->end.y = y;
  257.     if (ellipse->end.x == fix_x)
  258.     ellipse->start.x = x;
  259.     if (ellipse->end.y == fix_y)
  260.     ellipse->start.y = y;
  261.     if (ellipse->type == T_CIRCLE_BY_DIA) {
  262.     dx = ellipse->center.x = (fix_x + x) / 2 + .5;
  263.     dy = ellipse->center.y = (fix_y + y) / 2 + .5;
  264.     dx -= x;
  265.     dy -= y;
  266.     ellipse->radiuses.x = sqrt((double) (dx * dx + dy * dy)) + .5;
  267.     ellipse->radiuses.y = ellipse->radiuses.x;
  268.     } else {
  269.     ellipse->center.x = (fix_x + x) / 2;
  270.     ellipse->center.y = (fix_y + y) / 2;
  271.     ellipse->radiuses.x = abs(ellipse->center.x - fix_x);
  272.     ellipse->radiuses.y = abs(ellipse->center.y - fix_y);
  273.     }
  274.     draw_ellipse(ellipse, PAINT);
  275.     reset_cursor();
  276. }
  277.  
  278. static
  279. init_scale_ellipse()
  280. {
  281.     fix_x = cur_e->center.x;
  282.     fix_y = cur_e->center.y;
  283.     cur_angle = cur_e->angle;
  284.     if (from_x == fix_x && from_y == fix_y) {
  285.     put_msg("Center point selected, ignored");
  286.     return False;
  287.     }
  288.     set_action_on();
  289.     toggle_ellipsemarker(cur_e);
  290.     set_temp_cursor(crosshair_cursor);
  291.     canvas_locmove_proc = scaling_ellipse;
  292.     elastic_scaleellipse(cur_e);
  293.     canvas_middlebut_proc = fix_scale_ellipse;
  294.     canvas_rightbut_proc = cancel_scale_ellipse;
  295.     return True;        /* all is Ok */
  296. }
  297.  
  298. static
  299. cancel_scale_ellipse()
  300. {
  301.     elastic_scaleellipse(cur_e);
  302.     toggle_ellipsemarker(cur_e);
  303.     wrapup_scale();
  304. }
  305.  
  306. static
  307. fix_scale_ellipse(x, y)
  308.     int            x, y;
  309. {
  310.     elastic_scaleellipse(cur_e);
  311.     adjust_box_pos(x, y, from_x, from_y, &cur_x, &cur_y);
  312.     new_e = copy_ellipse(cur_e);
  313.     relocate_ellipsepoint(new_e, cur_x, cur_y);
  314.     change_ellipse(cur_e, new_e);
  315.     toggle_ellipsemarker(new_e);
  316.     wrapup_scale();
  317. }
  318.  
  319. static
  320. relocate_ellipsepoint(ellipse, x, y)
  321.     F_ellipse       *ellipse;
  322.     int            x, y;
  323. {
  324.     int            newx, newy, oldx, oldy;
  325.     float        newd, oldd, scalefact;
  326.  
  327.     set_temp_cursor(wait_cursor);
  328.     draw_ellipse(ellipse, ERASE);
  329.  
  330.     newx = x - fix_x;
  331.     newy = y - fix_y;
  332.     newd = sqrt((double) (newx * newx + newy * newy));
  333.     oldx = from_x - fix_x;
  334.     oldy = from_y - fix_y;
  335.     oldd = sqrt((double) (oldx * oldx + oldy * oldy));
  336.     scalefact = newd / oldd;
  337.  
  338.     ellipse->radiuses.x = ellipse->radiuses.x * scalefact;
  339.     ellipse->radiuses.y = ellipse->radiuses.y * scalefact;
  340.     ellipse->end.x = fix_x + (ellipse->end.x - fix_x) * scalefact;
  341.     ellipse->end.y = fix_y + (ellipse->end.y - fix_y) * scalefact;
  342.     ellipse->start.x = fix_x + (ellipse->start.x - fix_x) * scalefact;
  343.     ellipse->start.y = fix_y + (ellipse->start.y - fix_y) * scalefact;
  344.     draw_ellipse(ellipse, PAINT);
  345.     reset_cursor();
  346. }
  347.  
  348. /***************************  arc  *********************************/
  349.  
  350. static
  351. init_scale_arc()
  352. {
  353.     fix_x = cur_a->center.x;
  354.     fix_y = cur_a->center.y;
  355.     if (from_x == fix_x && from_y == fix_y) {
  356.     put_msg("Center point selected, ignored");
  357.     return False;
  358.     }
  359.     set_action_on();
  360.     toggle_arcmarker(cur_a);
  361.     elastic_scalearc(cur_a);
  362.     set_temp_cursor(crosshair_cursor);
  363.     canvas_locmove_proc = scaling_arc;
  364.     canvas_middlebut_proc = fix_scale_arc;
  365.     canvas_rightbut_proc = cancel_scale_arc;
  366.     return True;
  367. }
  368.  
  369. static
  370. cancel_scale_arc()
  371. {
  372.     elastic_scalearc(cur_a);
  373.     toggle_arcmarker(cur_a);
  374.     wrapup_scale();
  375. }
  376.  
  377. static
  378. fix_scale_arc(x, y)
  379.     int            x, y;
  380. {
  381.     elastic_scalearc(cur_a);
  382.     adjust_box_pos(x, y, from_x, from_y, &x, &y);
  383.     new_a = copy_arc(cur_a);
  384.     relocate_arcpoint(new_a, x, y);
  385.     change_arc(cur_a, new_a);
  386.     toggle_arcmarker(new_a);
  387.     wrapup_scale();
  388. }
  389.  
  390. static
  391. relocate_arcpoint(arc, x, y)
  392.     F_arc       *arc;
  393.     int            x, y;
  394. {
  395.     int            newx, newy, oldx, oldy;
  396.     float        newd, oldd, scalefact, xx, yy;
  397.     F_pos        p0, p1, p2;
  398.  
  399.     newx = x - fix_x;
  400.     newy = y - fix_y;
  401.     newd = sqrt((double) (newx * newx + newy * newy));
  402.  
  403.     oldx = from_x - fix_x;
  404.     oldy = from_y - fix_y;
  405.     oldd = sqrt((double) (oldx * oldx + oldy * oldy));
  406.  
  407.     scalefact = newd / oldd;
  408.  
  409.     p0 = arc->point[0];
  410.     p1 = arc->point[1];
  411.     p2 = arc->point[2];
  412.     p0.x = fix_x + (p0.x - fix_x) * scalefact;
  413.     p0.y = fix_y + (p0.y - fix_y) * scalefact;
  414.     p1.x = fix_x + (p1.x - fix_x) * scalefact;
  415.     p1.y = fix_y + (p1.y - fix_y) * scalefact;
  416.     p2.x = fix_x + (p2.x - fix_x) * scalefact;
  417.     p2.y = fix_y + (p2.y - fix_y) * scalefact;
  418.     if (compute_arccenter(p0, p1, p2, &xx, &yy)) {
  419.     set_temp_cursor(wait_cursor);
  420.     draw_arc(arc, ERASE);    /* erase old arc */
  421.     arc->point[0].x = p0.x;
  422.     arc->point[0].y = p0.y;
  423.     arc->point[1].x = p1.x;
  424.     arc->point[1].y = p1.y;
  425.     arc->point[2].x = p2.x;
  426.     arc->point[2].y = p2.y;
  427.     arc->center.x = xx;
  428.     arc->center.y = yy;
  429.     arc->direction = compute_direction(p0, p1, p2);
  430.     draw_arc(arc, PAINT);    /* draw new arc */
  431.     reset_cursor();
  432.     }
  433.     set_modifiedflag();
  434. }
  435.  
  436. /**************************  spline  *******************************/
  437.  
  438. static
  439. init_scale_spline()
  440. {
  441.     int            sumx, sumy, cnt;
  442.     F_point       *p;
  443.  
  444.     p = cur_s->points;
  445.     if (closed_spline(cur_s))
  446.     p = p->next;
  447.     for (sumx = 0, sumy = 0, cnt = 0; p != NULL; p = p->next) {
  448.     sumx = sumx + p->x;
  449.     sumy = sumy + p->y;
  450.     cnt++;
  451.     }
  452.     fix_x = sumx / cnt;
  453.     fix_y = sumy / cnt;
  454.     if (from_x == fix_x && from_y == fix_y) {
  455.     put_msg("Center point selected, ignored");
  456.     return False;
  457.     }
  458.     set_action_on();
  459.     set_temp_cursor(crosshair_cursor);
  460.     toggle_splinemarker(cur_s);
  461.     draw_spline(cur_s, ERASE);
  462.     elastic_scalepts(cur_s->points);
  463.     canvas_locmove_proc = scaling_spline;
  464.     canvas_middlebut_proc = fix_scale_spline;
  465.     canvas_rightbut_proc = cancel_scale_spline;
  466.     return True;
  467. }
  468.  
  469. static
  470. cancel_scale_spline()
  471. {
  472.     elastic_scalepts(cur_s->points);
  473.     draw_spline(cur_s, PAINT);
  474.     toggle_splinemarker(cur_s);
  475.     wrapup_scale();
  476. }
  477.  
  478. static
  479. fix_scale_spline(x, y)
  480.     int            x, y;
  481. {
  482.     elastic_scalepts(cur_s->points);
  483.     adjust_box_pos(x, y, from_x, from_y, &x, &y);
  484.     /* make a copy of the original and save as unchanged object */
  485.     old_s = copy_spline(cur_s);
  486.     clean_up();
  487.     set_latestspline(old_s);
  488.     set_action_object(F_CHANGE, O_SPLINE);
  489.     old_s->next = cur_s;
  490.     /* now change the original to become the new object */
  491.     rescale_points(cur_s->points, x, y);
  492.     if (int_spline(cur_s))
  493.     remake_control_points(cur_s);
  494.     draw_spline(cur_s, PAINT);
  495.     toggle_splinemarker(cur_s);
  496.     wrapup_scale();
  497. }
  498.  
  499. /***************************  compound    ********************************/
  500.  
  501. static        Boolean
  502. init_boxscale_compound(x, y)
  503.     int            x, y;
  504. {
  505.     int            xmin, ymin, xmax, ymax;
  506.     double        dx, dy, l;
  507.  
  508.     xmin = min2(cur_c->secorner.x, cur_c->nwcorner.x);
  509.     ymin = min2(cur_c->secorner.y, cur_c->nwcorner.y);
  510.     xmax = max2(cur_c->secorner.x, cur_c->nwcorner.x);
  511.     ymax = max2(cur_c->secorner.y, cur_c->nwcorner.y);
  512.  
  513.     if (xmin == xmax || ymin == ymax) {
  514.     put_msg("Can't use box scale on selected object");
  515.     return False;
  516.     }
  517.     set_action_on();
  518.     toggle_compoundmarker(cur_c);
  519.     draw_compoundelements(cur_c, ERASE);
  520.     set_temp_cursor(crosshair_cursor);
  521.  
  522.     if (x == xmin) {
  523.     fix_x = xmax;
  524.     from_x = x;
  525.     if (y == ymin) {
  526.         fix_y = ymax;
  527.         from_y = y;
  528.         constrained = BOX_SCALE;
  529.     } else if (y == ymax) {
  530.         fix_y = ymin;
  531.         from_y = y;
  532.         constrained = BOX_SCALE;
  533.     } else {
  534.         fix_y = ymax;
  535.         from_y = ymin;
  536.         constrained = BOX_HSTRETCH;
  537.     }
  538.     } else if (x == xmax) {
  539.     fix_x = xmin;
  540.     from_x = x;
  541.     if (y == ymin) {
  542.         fix_y = ymax;
  543.         from_y = y;
  544.         constrained = BOX_SCALE;
  545.     } else if (y == ymax) {
  546.         fix_y = ymin;
  547.         from_y = y;
  548.         constrained = BOX_SCALE;
  549.     } else {
  550.         fix_y = ymax;
  551.         from_y = ymin;
  552.         constrained = BOX_HSTRETCH;
  553.     }
  554.     } else {
  555.     if (y == ymin) {
  556.         fix_y = ymax;
  557.         from_y = y;
  558.         fix_x = xmax;
  559.         from_x = xmin;
  560.         constrained = BOX_VSTRETCH;
  561.     } else {        /* y == ymax */
  562.         fix_y = ymin;
  563.         from_y = y;
  564.         fix_x = xmax;
  565.         from_x = xmin;
  566.         constrained = BOX_VSTRETCH;
  567.     }
  568.     }
  569.  
  570.     cur_x = from_x;
  571.     cur_y = from_y;
  572.  
  573.     if (constrained == BOX_SCALE) {
  574.     dx = (double) (cur_x - fix_x);
  575.     dy = (double) (cur_y - fix_y);
  576.     l = sqrt(dx * dx + dy * dy);
  577.     cosa = fabs(dx / l);
  578.     sina = fabs(dy / l);
  579.     }
  580.     elastic_box(fix_x, fix_y, cur_x, cur_y);
  581.     canvas_locmove_proc = constrained_resizing_box;
  582.     canvas_leftbut_proc = fix_boxscale_compound;
  583.     canvas_rightbut_proc = cancel_boxscale_compound;
  584.     return True;
  585. }
  586.  
  587. static
  588. cancel_boxscale_compound()
  589. {
  590.     elastic_box(fix_x, fix_y, cur_x, cur_y);
  591.     draw_compoundelements(cur_c, PAINT);
  592.     toggle_compoundmarker(cur_c);
  593.     wrapup_scale();
  594. }
  595.  
  596. static
  597. fix_boxscale_compound(x, y)
  598.     int            x, y;
  599. {
  600.     float        scalex, scaley;
  601.  
  602.     elastic_box(fix_x, fix_y, cur_x, cur_y);
  603.     adjust_box_pos(x, y, from_x, from_y, &x, &y);
  604.     new_c = copy_compound(cur_c);
  605.     scalex = ((float) (x - fix_x)) / (from_x - fix_x);
  606.     scaley = ((float) (y - fix_y)) / (from_y - fix_y);
  607.     scale_compound(new_c, scalex, scaley, fix_x, fix_y);
  608.     change_compound(cur_c, new_c);
  609.     draw_compoundelements(new_c, PAINT);
  610.     toggle_compoundmarker(new_c);
  611.     wrapup_scale();
  612. }
  613.  
  614. static
  615. init_scale_compound()
  616. {
  617.     fix_x = (cur_c->nwcorner.x + cur_c->secorner.x) / 2;
  618.     fix_y = (cur_c->nwcorner.y + cur_c->secorner.y) / 2;
  619.     set_action_on();
  620.     toggle_compoundmarker(cur_c);
  621.     set_temp_cursor(crosshair_cursor);
  622.     draw_compoundelements(cur_c, ERASE);
  623.     elastic_scalecompound(cur_c);
  624.     canvas_locmove_proc = scaling_compound;
  625.     canvas_middlebut_proc = fix_scale_compound;
  626.     canvas_rightbut_proc = cancel_scale_compound;
  627. }
  628.  
  629. static
  630. cancel_scale_compound()
  631. {
  632.     elastic_scalecompound(cur_c);
  633.     draw_compoundelements(cur_c, PAINT);
  634.     toggle_compoundmarker(cur_c);
  635.     wrapup_scale();
  636. }
  637.  
  638. static
  639. fix_scale_compound(x, y)
  640.     int            x, y;
  641. {
  642.     elastic_scalecompound(cur_c);
  643.     adjust_box_pos(x, y, from_x, from_y, &cur_x, &cur_y);
  644.     /* make a copy of the original and save as unchanged object */
  645.     old_c = copy_compound(cur_c);
  646.     clean_up();
  647.     set_latestcompound(old_c);
  648.     set_action_object(F_CHANGE, O_COMPOUND);
  649.     old_c->next = cur_c;
  650.     /* now change the original to become the new object */
  651.     prescale_compound(cur_c, cur_x, cur_y);
  652.     draw_compoundelements(cur_c, PAINT);
  653.     toggle_compoundmarker(cur_c);
  654.     wrapup_scale();
  655. }
  656.  
  657. static int
  658. prescale_compound(c, x, y)
  659.     F_compound       *c;
  660.     int            x, y;
  661. {
  662.     int            newx, newy, oldx, oldy;
  663.     float        newd, oldd, scalefact;
  664.  
  665.     newx = x - fix_x;
  666.     newy = y - fix_y;
  667.     newd = sqrt((double) (newx * newx + newy * newy));
  668.     oldx = from_x - fix_x;
  669.     oldy = from_y - fix_y;
  670.     oldd = sqrt((double) (oldx * oldx + oldy * oldy));
  671.     scalefact = newd / oldd;
  672.     scale_compound(c, scalefact, scalefact, fix_x, fix_y);
  673. }
  674.  
  675. scale_compound(c, sx, sy, refx, refy)
  676.     F_compound       *c;
  677.     float        sx, sy;
  678.     int            refx, refy;
  679. {
  680.     F_line       *l;
  681.     F_spline       *s;
  682.     F_ellipse       *e;
  683.     F_text       *t;
  684.     F_arc       *a;
  685.     F_compound       *c1;
  686.     int            x1, y1, x2, y2;
  687.  
  688.     x1 = round(refx + (c->nwcorner.x - refx) * sx);
  689.     y1 = round(refy + (c->nwcorner.y - refy) * sy);
  690.     x2 = round(refx + (c->secorner.x - refx) * sx);
  691.     y2 = round(refy + (c->secorner.y - refy) * sy);
  692.     c->nwcorner.x = min2(x1, x2);
  693.     c->nwcorner.y = min2(y1, y2);
  694.     c->secorner.x = max2(x1, x2);
  695.     c->secorner.y = max2(y1, y2);
  696.  
  697.     for (l = c->lines; l != NULL; l = l->next) {
  698.     scale_line(l, sx, sy, refx, refy);
  699.     }
  700.     for (s = c->splines; s != NULL; s = s->next) {
  701.     scale_spline(s, sx, sy, refx, refy);
  702.     }
  703.     for (a = c->arcs; a != NULL; a = a->next) {
  704.     scale_arc(a, sx, sy, refx, refy);
  705.     }
  706.     for (e = c->ellipses; e != NULL; e = e->next) {
  707.     scale_ellipse(e, sx, sy, refx, refy);
  708.     }
  709.     for (t = c->texts; t != NULL; t = t->next) {
  710.     scale_text(t, sx, sy, refx, refy);
  711.     }
  712.     for (c1 = c->compounds; c1 != NULL; c1 = c1->next) {
  713.     scale_compound(c1, sx, sy, refx, refy);
  714.     }
  715. }
  716.  
  717. scale_line(l, sx, sy, refx, refy)
  718.     F_line       *l;
  719.     float        sx, sy;
  720.     int            refx, refy;
  721. {
  722.     F_point       *p;
  723.  
  724.     for (p = l->points; p != NULL; p = p->next) {
  725.     p->x = round(refx + (p->x - refx) * sx);
  726.     p->y = round(refy + (p->y - refy) * sy);
  727.     }
  728. }
  729.  
  730. scale_spline(s, sx, sy, refx, refy)
  731.     F_spline       *s;
  732.     float        sx, sy;
  733.     int            refx, refy;
  734. {
  735.     F_point       *p;
  736.     F_control       *c;
  737.  
  738.     for (p = s->points; p != NULL; p = p->next) {
  739.     p->x = round(refx + (p->x - refx) * sx);
  740.     p->y = round(refy + (p->y - refy) * sy);
  741.     }
  742.     for (c = s->controls; c != NULL; c = c->next) {
  743.     c->lx = refx + (c->lx - refx) * sx;
  744.     c->ly = refy + (c->ly - refy) * sy;
  745.     c->rx = refx + (c->rx - refx) * sx;
  746.     c->ry = refy + (c->ry - refy) * sy;
  747.     }
  748. }
  749.  
  750. scale_arc(a, sx, sy, refx, refy)
  751.     F_arc       *a;
  752.     float        sx, sy;
  753.     int            refx, refy;
  754. {
  755.     int            i;
  756.  
  757.     for (i = 0; i < 3; i++) {
  758.     a->point[i].x = round(refx + (a->point[i].x - refx) * sx);
  759.     a->point[i].y = round(refy + (a->point[i].y - refy) * sy);
  760.     }
  761.     compute_arccenter(a->point[0], a->point[1], a->point[2],
  762.               &a->center.x, &a->center.y);
  763.     a->direction = compute_direction(a->point[0], a->point[1], a->point[2]);
  764. }
  765.  
  766. scale_ellipse(e, sx, sy, refx, refy)
  767.     F_ellipse       *e;
  768.     float        sx, sy;
  769.     int            refx, refy;
  770. {
  771.     e->center.x = round(refx + (e->center.x - refx) * sx);
  772.     e->center.y = round(refy + (e->center.y - refy) * sy);
  773.     e->start.x = round(refx + (e->start.x - refx) * sx);
  774.     e->start.y = round(refy + (e->start.y - refy) * sy);
  775.     e->end.x = round(refx + (e->end.x - refx) * sx);
  776.     e->end.y = round(refy + (e->end.y - refy) * sy);
  777.     e->radiuses.x = abs(round(e->radiuses.x * sx));
  778.     e->radiuses.y = abs(round(e->radiuses.y * sy));
  779.     /* if this WAS a circle and is NOW an ellipse, change type to reflect */
  780.     if (e->type == T_CIRCLE_BY_RAD || e->type == T_CIRCLE_BY_DIA) {
  781.     if (e->radiuses.x != e->radiuses.y)
  782.         e->type -= 2;
  783.     }
  784.     /* conversely, if this WAS an ellipse and is NOW a circle, change type */
  785.     else if (e->type == T_ELLIPSE_BY_RAD || e->type == T_ELLIPSE_BY_DIA) {
  786.     if (e->radiuses.x == e->radiuses.y)
  787.         e->type += 2;
  788.     }
  789. }
  790.  
  791. scale_text(t, sx, sy, refx, refy)
  792.     F_text       *t;
  793.     float        sx, sy;
  794.     int            refx, refy;
  795. {
  796.     t->base_x = round(refx + (t->base_x - refx) * sx);
  797.     t->base_y = round(refy + (t->base_y - refy) * sy);
  798.     if (!rigid_text(t)) {
  799.     t->size = round(t->size * sx);
  800.     t->height = round(t->height * sx);
  801.     t->length = round(t->length * sx);
  802.     }
  803.     /* rescale font */
  804.     reload_text_fstruct(t);
  805. }
  806.  
  807.  
  808. /***************************  line  ********************************/
  809.  
  810. static        Boolean
  811. init_boxscale_line(x, y)
  812.     int            x, y;
  813. {
  814.     int            xmin, ymin, xmax, ymax;
  815.     F_point       *p0, *p1, *p2;
  816.     double        dx, dy, l;
  817.  
  818.     if (cur_l->type != T_BOX &&
  819.     cur_l->type != T_ARC_BOX &&
  820.     cur_l->type != T_EPS_BOX) {
  821.     put_msg("Can't use box scale on selected object");
  822.     return False;
  823.     }
  824.     p0 = cur_l->points;
  825.     p1 = p0->next;
  826.     p2 = p1->next;
  827.     xmin = min3(p0->x, p1->x, p2->x);
  828.     ymin = min3(p0->y, p1->y, p2->y);
  829.     xmax = max3(p0->x, p1->x, p2->x);
  830.     ymax = max3(p0->y, p1->y, p2->y);
  831.  
  832.     if (xmin == xmax || ymin == ymax) {
  833.     put_msg("Can't use box scale on selected object");
  834.     return False;
  835.     }
  836.     set_action_on();
  837.     toggle_linemarker(cur_l);
  838.  
  839.     if (x == xmin) {
  840.     fix_x = xmax;
  841.     from_x = x;
  842.     if (y == ymin) {
  843.         fix_y = ymax;
  844.         from_y = y;
  845.         constrained = BOX_SCALE;
  846.     } else if (y == ymax) {
  847.         fix_y = ymin;
  848.         from_y = y;
  849.         constrained = BOX_SCALE;
  850.     } else {
  851.         fix_y = ymax;
  852.         from_y = ymin;
  853.         constrained = BOX_HSTRETCH;
  854.     }
  855.     } else if (x == xmax) {
  856.     fix_x = xmin;
  857.     from_x = x;
  858.     if (y == ymin) {
  859.         fix_y = ymax;
  860.         from_y = y;
  861.         constrained = BOX_SCALE;
  862.     } else if (y == ymax) {
  863.         fix_y = ymin;
  864.         from_y = y;
  865.         constrained = BOX_SCALE;
  866.     } else {
  867.         fix_y = ymax;
  868.         from_y = ymin;
  869.         constrained = BOX_HSTRETCH;
  870.     }
  871.     } else {
  872.     if (y == ymin) {
  873.         fix_y = ymax;
  874.         from_y = y;
  875.         fix_x = xmax;
  876.         from_x = xmin;
  877.         constrained = BOX_VSTRETCH;
  878.     } else {        /* y == ymax */
  879.         fix_y = ymin;
  880.         from_y = y;
  881.         fix_x = xmax;
  882.         from_x = xmin;
  883.         constrained = BOX_VSTRETCH;
  884.     }
  885.     }
  886.  
  887.     cur_x = from_x;
  888.     cur_y = from_y;
  889.     set_temp_cursor(crosshair_cursor);
  890.     draw_line(cur_l, ERASE);
  891.  
  892.     if (constrained == BOX_SCALE) {
  893.     dx = (double) (cur_x - fix_x);
  894.     dy = (double) (cur_y - fix_y);
  895.     l = sqrt(dx * dx + dy * dy);
  896.     cosa = fabs(dx / l);
  897.     sina = fabs(dy / l);
  898.     }
  899.     elastic_box(fix_x, fix_y, cur_x, cur_y);
  900.     canvas_locmove_proc = constrained_resizing_box;
  901.     canvas_leftbut_proc = fix_boxscale_line;
  902.     canvas_rightbut_proc = cancel_boxscale_line;
  903.     return True;
  904. }
  905.  
  906. static
  907. cancel_boxscale_line()
  908. {
  909.     elastic_box(fix_x, fix_y, cur_x, cur_y);
  910.     draw_line(cur_l, PAINT);
  911.     toggle_linemarker(cur_l);
  912.     wrapup_scale();
  913. }
  914.  
  915. static
  916. fix_boxscale_line(x, y)
  917.     int            x, y;
  918. {
  919.     elastic_box(fix_x, fix_y, cur_x, cur_y);
  920.     adjust_box_pos(x, y, from_x, from_y, &x, &y);
  921.     new_l = copy_line(cur_l);
  922.     draw_line(cur_l, ERASE);
  923.     assign_newboxpoint(new_l, fix_x, fix_y, x, y);
  924.     if (new_l->type == T_EPS_BOX) {
  925.     if (signof(fix_x - from_x) != signof(fix_x - x))
  926.         new_l->eps->flipped = 1 - new_l->eps->flipped;
  927.     if (signof(fix_y - from_y) != signof(fix_y - y))
  928.         new_l->eps->flipped = 1 - new_l->eps->flipped;
  929.     }
  930.     change_line(cur_l, new_l);
  931.     draw_line(new_l, PAINT);
  932.     toggle_linemarker(new_l);
  933.     wrapup_scale();
  934. }
  935.  
  936. static
  937. assign_newboxpoint(b, x1, y1, x2, y2)
  938.     F_line       *b;
  939.     int            x1, y1, x2, y2;
  940. {
  941.     F_point       *p;
  942.  
  943.     p = b->points;
  944.     if (p->x != x1)
  945.     p->x = x2;
  946.     if (p->y != y1)
  947.     p->y = y2;
  948.     p = p->next;
  949.     if (p->x != x1)
  950.     p->x = x2;
  951.     if (p->y != y1)
  952.     p->y = y2;
  953.     p = p->next;
  954.     if (p->x != x1)
  955.     p->x = x2;
  956.     if (p->y != y1)
  957.     p->y = y2;
  958.     p = p->next;
  959.     if (p->x != x1)
  960.     p->x = x2;
  961.     if (p->y != y1)
  962.     p->y = y2;
  963.     p = p->next;
  964.     if (p->x != x1)
  965.     p->x = x2;
  966.     if (p->y != y1)
  967.     p->y = y2;
  968. }
  969.  
  970. static
  971. init_scale_line()
  972. {
  973.     int            sumx, sumy, cnt;
  974.     F_point       *p;
  975.  
  976.     p = cur_l->points;
  977.     if (cur_l->type != T_POLYLINE)
  978.     p = p->next;
  979.     for (sumx = 0, sumy = 0, cnt = 0; p != NULL; p = p->next) {
  980.     sumx = sumx + p->x;
  981.     sumy = sumy + p->y;
  982.     cnt++;
  983.     }
  984.     fix_x = sumx / cnt;
  985.     fix_y = sumy / cnt;
  986.     if (from_x == fix_x && from_y == fix_y) {
  987.     put_msg("Center point selected, ignored");
  988.     return False;
  989.     }
  990.     set_action_on();
  991.     toggle_linemarker(cur_l);
  992.     set_temp_cursor(crosshair_cursor);
  993.     draw_line(cur_l, ERASE);
  994.     elastic_scalepts(cur_l->points);
  995.     canvas_locmove_proc = scaling_line;
  996.     canvas_middlebut_proc = fix_scale_line;
  997.     canvas_rightbut_proc = cancel_scale_line;
  998.     return True;
  999. }
  1000.  
  1001. static
  1002. cancel_scale_line()
  1003. {
  1004.     elastic_scalepts(cur_l->points);
  1005.     draw_line(cur_l, PAINT);
  1006.     toggle_linemarker(cur_l);
  1007.     wrapup_scale();
  1008. }
  1009.  
  1010. static
  1011. fix_scale_line(x, y)
  1012.     int            x, y;
  1013. {
  1014.     elastic_scalepts(cur_l->points);
  1015.     adjust_box_pos(x, y, from_x, from_y, &x, &y);
  1016.     /* make a copy of the original and save as unchanged object */
  1017.     old_l = copy_line(cur_l);
  1018.     clean_up();
  1019.     set_latestline(old_l);
  1020.     set_action_object(F_CHANGE, O_POLYLINE);
  1021.     old_l->next = cur_l;
  1022.     /* now change the original to become the new object */
  1023.     rescale_points(cur_l->points, x, y);
  1024.     draw_line(cur_l, PAINT);
  1025.     toggle_linemarker(cur_l);
  1026.     wrapup_scale();
  1027. }
  1028.  
  1029. static
  1030. rescale_points(pts, x, y)
  1031.     F_point       *pts;
  1032.     int            x, y;
  1033. {
  1034.     F_point       *p;
  1035.     int            newx, newy, oldx, oldy;
  1036.     float        newd, oldd, scalefact;
  1037.  
  1038.     p = pts;
  1039.     newx = x - fix_x;
  1040.     newy = y - fix_y;
  1041.     newd = sqrt((double) (newx * newx + newy * newy));
  1042.  
  1043.     oldx = from_x - fix_x;
  1044.     oldy = from_y - fix_y;
  1045.     oldd = sqrt((double) (oldx * oldx + oldy * oldy));
  1046.  
  1047.     scalefact = newd / oldd;
  1048.     for (p = pts; p != NULL; p = p->next) {
  1049.     p->x = fix_x + (p->x - fix_x) * scalefact;
  1050.     p->y = fix_y + (p->y - fix_y) * scalefact;
  1051.     }
  1052.     set_modifiedflag();
  1053. }
  1054.